<?php
Class Server
{
    private $server;
    const host = '0.0.0.0';
    const port = '9503';

    public function __construct()
    {
        $this->server = new Swoole\WebSocket\Server(self::host, self::port);
        $this->server->set([
            'reactor_num'   => 2,     // 启动的线程数
            'worker_num'    => 4,     // 设置启动的进程数
            'backlog'       => 128,   // 队列长度
            'max_request'   => 100,  //最大请求数
            'dispatch_mode' => 4, //数据包分发策略
            'task_worker_num' => 4, //执行异步任务
            'daemonize' => 1,  //守护进程
            'log_file' => 'swoole.log',  //日志
            'log_level' => SWOOLE_LOG_TRACE,  //日志级别
            'trace_flags' => SWOOLE_TRACE_SERVER | SWOOLE_TRACE_HTTP2,
        ]);
        $this->server->on('Start', [$this, 'onStart']);
        $this->server->on('Open', [$this, 'onOpen']);
        $this->server->on('Message', [$this, 'onMessage']);
        $this->server->on('Close', [$this, 'onClose']);
        $this->server->on('Task', [$this, 'onTask']);
        $this->server->on('Finish', [$this, 'onFinish']);
        $this->server->on('Request', [$this, 'onRequest']);

        $this->server->start();
    }


    public function onStart($server){
        echo "#### onStart ####".PHP_EOL;
        echo "SWOOLE ".SWOOLE_VERSION . " 服务已启动".PHP_EOL;
        echo "master_pid: {$server->master_pid}".PHP_EOL;
        echo "manager_pid: {$server->manager_pid}".PHP_EOL;
        echo "########".PHP_EOL.PHP_EOL;
    }

    public function onOpen($server, $request) {
        echo "#### onOpen ####".PHP_EOL;
        echo "server: handshake success with fd{$request->fd}".PHP_EOL;
        $server->task([
            'type' => 'login'
        ]);
        echo "########".PHP_EOL.PHP_EOL;
    }

    public function onMessage($server, $frame) {
        echo "#### onMessage ####".PHP_EOL;
        echo "receive from fd{$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}".PHP_EOL;
        $server->task(['type' => 'speak', 'msg' => $frame->data]);
        echo "########".PHP_EOL.PHP_EOL;
    }

    public function onClose($server, $fd) {
        echo "#### onClose ####".PHP_EOL;
        echo "client {$fd} closed".PHP_EOL;
        echo "########".PHP_EOL.PHP_EOL;
    }

    public function onTask($server, $task_id, $from_id, $data) {
        echo "#### onTask ####".PHP_EOL;
        echo "#{$server->worker_id} onTask: [PID={$server->worker_pid}]: task_id={$task_id}".PHP_EOL;
        $msg = '';
        switch ($data['type']) {
            case 'login':
                $msg = json_encode(2000);
                break;
            case 'speak':
                $msg = $data['msg'];
                break;
        }
        foreach ($server->connections as $fd) {
            $connectionInfo = $server->connection_info($fd);
            if ($connectionInfo['websocket_status'] == 3) {
                $server->push($fd, $msg); //长度最大不得超过2M
            }
        }
        $server->finish($data);
        echo "########".PHP_EOL.PHP_EOL;
    }

    public function onFinish($server,$task_id, $data) {
        echo "#### onFinish ####".PHP_EOL;
        echo "Task {$task_id} 已完成".PHP_EOL;
        echo "########".PHP_EOL.PHP_EOL;
    }

    public function onRequest($request, $response)
    {
        echo "#### onRequest ####".PHP_EOL;
        foreach ($this->server->connections as $fd) {
            // 需要先判断是否是正确的websocket连接，否则有可能会push失败
            if ($this->server->isEstablished($fd)) {
                $this->server->push($fd, $request->post['data']);
            }
        }
        echo "client is PushMessage :".json_encode($request->post['data']).PHP_EOL;
        echo "########".PHP_EOL.PHP_EOL;
    }
}

new Server();